#include <stdio.h>
#include <stdlib.h>

#include "lua.h"
#include "lauxlib.h"
#include "ddcrypt.h"

static int
l_base64_encode(lua_State * L){
    size_t len;
    const char * s = luaL_checklstring(L, 1, &len);
    if(!s)
        return 0;
    char * ds = malloc(len);
    dd_base64_encode(s, len, ds);
    lua_pushlstring(L, ds, len);
    free(ds);
    return 1;
}

static int
l_base64_decode(lua_State * L){
    size_t len;
    const char * s = luaL_checklstring(L, 1, &len);
    if(!s)
        return 0;
    char * ds = malloc(len);
    dd_base64_decode(s, len, ds);
    lua_pushlstring(L, ds, len);
    free(ds);
    return 1;
}

static int
l_sign_with_rsa(lua_State * L){
    size_t data_len;
    const char * data = luaL_checklstring(L, 1, &data_len);
    size_t key_len;
    const char * key = luaL_checklstring(L, 2, &key_len);
    if(!data || !key)
        return 0;
    int private = lua_toboolean(L, 3);
    const char * sign_type = luaL_checkstring(L, 4);
    if(!sign_type)
        return 0;
    if(strcmp(sign_type, "md5") != 0)
        return 0;

    EVP_PKEY * pk = dd_get_rsa_PKCS1_key(key, key_len, private);
    if (!pk)
        return 0;
    uint32_t sign_len = EVP_PKEY_size(pk);
    uint8_t * signs = malloc(sign_len * 2);
    memset(signs, 0, sign_len * 2);
    int ret = dd_sign_with_rsa(data, data_len, signs, EVP_md5(), pk);
    if (ret == 0){
        free(signs);
        lua_pushstring(L, signs);
        return 1;
    }
    free(signs);
    return 0;
}

int
luaopen_ddcrypt(lua_State * L){
    luaL_checkversion(L);
    luaL_Reg l[] = {
        {"base64_encode", l_base64_encode},
        {"base64_decode", l_base64_decode},
        {"sign_with_rsa", l_sign_with_rsa},
        {NULL, NULL}
    };
    luaL_newlib(L, l);
    return 1;
}